package io.vector.study.algorithm.linkedlist;

import java.util.function.Consumer;

/**
 * Created by vector on 2017/3/21.
 */
public class LinkedList<E> {

    private static class Node<E> {
        E item;
        Node<E> next;

        public Node(E item, Node<E> next) {
            this.item = item;
            this.next = next;
        }
    }

    private Node<E> first;

    private int size = 0;

    public void add(E item) {
        if (first == null) {
            first = new Node<E>(item, null);
        } else {
            appendNode(new Node<E>(item, null));
        }
    }

    private void appendNode(Node<E> node) {
        Node<E> iterator = first;
        while (iterator.next != null) {
            iterator = iterator.next;
        }
        iterator.next = node;
        ++size;
    }

    public int size() {
        return size;
    }

    public void reverseLoopImpl() {
        if (first == null || first.next == null) {
            return ;
        }

        Node<E> newFirst = first,
                node = first.next;
        while (node != null) {
            first.next = node.next;
            node.next = newFirst;
            newFirst = node;
            node = first.next;
        }
        first = newFirst;
    }

    public void reverseRecursionImpl() {
        if (first == null || first.next == null) {
            return ;
        }

        first = reverseRecursionImpl(first);
    }

    private Node<E> reverseRecursionImpl(Node<E> node) {
        if (node.next == null) {
            return node;
        }

        Node<E> newFirst = reverseRecursionImpl(node.next);
        Node<E> tail = node.next;
        tail.next = node;
        node.next = null;
        return newFirst;
    }

    public void swapPairNode() {
        Node<E> node = first,
                preNode = null,
                left = null,
                right = null;

        while (node != null && node.next != null) {
            left = node;
            right = left.next;

            left.next = right.next;
            right.next = left;
            if (preNode != null) {
                preNode.next = right;
            } else {
                first = right;
            }

            preNode = left;
            node = left.next;
        }
    }

    public void foreach(Consumer<E> consumer) {
        if (first == null) {
            return ;
        }

        Node<E> iterator = first;
        while (iterator != null) {
            consumer.accept(iterator.item);
            iterator = iterator.next;
        }
    }

}
